﻿// Version posterior mejorada/simplificada a arKristal_v1.02

// Version 2.0

package motor.colision {
	
	import flash.display.*;
	
	public class Cuerpos {
				
		public static var TIPO_GRUPO_A:int = 1;
		public static var TIPO_GRUPO_B:int = 2;
				
		public var grupoA:Array;
		public var grupoB:Array;
		
		private static var instancia:Cuerpos = null;
		
		private var colisionMenorCalculada:Colision; 
		// Si es NULL hay q recalcular
		
		
		public function Cuerpos () // deberia ser privada por ser Singleton, pero Flash no me lo permite
		{
			if (instancia != null)
			{
				trace ("Error!: Cuerpos, se deberia crear solo una instancia!");
			}
				
			grupoA = new Array();
			grupoB = new Array();
			
			colisionMenorCalculada=null;
		}
		
		public static function getInstancia():Cuerpos
		{
			if (instancia == null)
			{
				instancia = new Cuerpos ();
				
				trace ("Cuerpos instancia NULL");
			}
			return instancia;
		}	
		
		private function agregarGrupoA (unCuerpo:Cuerpo):void
		{
			//NO DEBE HABER REPETIDOS!
			if (estaEnArray(grupoA,unCuerpo)==-1)
			{
				grupoA.push(unCuerpo);
				colisionMenorCalculada=null;//Hay q recalcular debido al nuevo estado.
			}
			else trace ("Warning: Cuerpos.agregarFijo, este cuerpo ya estaba en la coleccion!");
		}
		
		private function agregarGrupoB (unCuerpo:Cuerpo):void
		{
			//NO DEBE HABER REPETIDOS!
			if (estaEnArray(grupoB,unCuerpo)==-1)
			{
				grupoB.push(unCuerpo);
				colisionMenorCalculada=null;//Hay q recalcular debido al nuevo estado.
			}
			else trace ("Warning: Cuerpos.agregarFijo, este cuerpo ya estaba en la coleccion!");
		}
		
		public function animarHasta (unTiempo:Number):void
		{
			var i:int;
			for (i=0;i<=grupoA.length-1;i++)
			{				
				grupoA[i].animarHasta(unTiempo);
			}
			for (i=0;i<=grupoB.length-1;i++)
			{
				grupoB[i].animarHasta(unTiempo);				
			}
		}
		
		public function colisionCuerposGrupoAGrupoB ():Colision
		{
			var colision:Colision=null;
			var cm:Colision=null;			
			var i,j:int;
			//Solo necesito la colision Menor, luego de ejecutarla recalculo
			
			if (grupoA.length==0) return null;
			if (grupoB.length==0) return null;
									
			for (i=0;i<=grupoA.length-1;i++)
			{				
				/*Haciendo j=i+1 evito q haya colisiones repetidas!!!*/
				for (j=0;j<=grupoB.length-1;j++)
				{					
					//trace ("LineaTiempo: colisionCuerposMovilesFijos: i:",i," j:",j);
					colision=Cuerpo(grupoA[i]).seColisionan (Cuerpo(grupoB[j]));
					
					if (colision!=null)
					{												
							if (cm==null)
							{
								cm=colision;
							} else
							{
								if (cm.tiempoColision>colision.tiempoColision)
								{
									cm=colision;
								}
							}
					}
					/*----*/					
				}			
				/*----*/				
			}
			//trace ("La colision menor es: ",cm);
			return cm;
		}
		
		public function colisionMenor ():Colision
		{
			if (colisionMenorCalculada!=null)
			{
				return colisionMenorCalculada;
			}
				
			var cm:Colision=null;
			var colision:Colision=null;
			
			if (grupoA.length==0)
			{
				return null;
			}
			if (grupoB.length==0)
			{
				return null;
			}			
			/*----*/
			if (! ( (grupoA.length==0) || (grupoB.length==0)))
			{				
				colision=colisionCuerposGrupoAGrupoB ();
				if (cm==null)
				{
					cm=colision;
				} else
				{
					if (colision!=null)
					{
						if (colision.tiempoColision<cm.tiempoColision) cm=colision;
					}
				}
			}
				
			colisionMenorCalculada=cm;
			
			return colisionMenorCalculada;
		}
		
						
		public function calcularEfectosColision ():void
		{			
			if (colisionMenorCalculada==null)
			{
				trace ("Error: Cuerpos.calcularEfectosColision: La colisionMenorCalculada==null.");
				return;
			}
				
			colisionMenorCalculada.dispararColision();			
				
			colisionMenorCalculada = null;			
		}		
		
				
		public function destruir ():void
		{
			var i:int;
			for (i=0;i<=grupoA.length-1;i++)
			{
					Cuerpo(grupoA[i]).destroy();
			}
			for (i=0;i<=grupoB.length-1;i++)
			{
					Cuerpo(grupoB[i]).destroy();
			}
			/*----*/
			grupoA=null;
			grupoB=null;
			instancia=null;
			/*----*/						
			colisionMenorCalculada = null;
		}		
		
		private function estaEnArray (unArray:Array, elemento:Object):Number
		{
			var encontro:Boolean=false;
			var i:Number=0;
			//----
			while ((i<unArray.length) && (!encontro))
			{
				if (unArray[i] == elemento)
				{
					encontro=true;
				} else
				{
					i++;
				}
			}
			
			if (encontro) return i; else return -1;
		}
		
		/*
		public function reemplazarCuerpo (cuerpoViejo:Cuerpo, cuerpoNuevo:Cuerpo):void
		{			
			var i:Number=estaEnArray(cuerposFijos,cuerpoViejo);
			if (i!=-1)
			{
				agregarFijo(cuerpoNuevo);
				cuerpoViejo.destroy();
				cuerpoNuevo.agregarAEscena(escena);
				return;
			}
			//----
			i=estaEnArray(cuerposMoviles,cuerpoViejo);			
			if (i!=-1)
			{
				agregarMovil(cuerpoNuevo);
				cuerpoViejo.destroy();
				cuerpoNuevo.agregarAEscena(escena);
				return;
			}
			trace ("Error: Cuerpos.reemplazarCuerpo: No se encontro el cuerpoViejo");
			return;
		}	
		*/
		
		public function actualizarColision ():void
		{
			//Sirve para cuando los cuerpos no predecibles se comportan de forma impredecible!!!
			colisionMenorCalculada = null;
		}
		
		public function actualizarColisionMenor_tiempoTranscurrido (unTiempo:Number):void
		{
			if (colisionMenorCalculada == null)
			{
				trace ("Error: Cuerpos.actualizarColisionMenor_tiempoTranscurrido: No hay colision q actualizar.");
				return;
			}
			colisionMenorCalculada.tiempoColision -= unTiempo;
			if (colisionMenorCalculada.tiempoColision<0)
			{
				trace ("Error: Cuerpos.actualizarColisionMenor_tiempoTranscurrido: El tiempo de ocurrencia de la colision es NEGATIVO!!!");
			}
		}
		
		public function crearCuerpoGrupo (xx:Number, yy:Number, velX:Number, velY:Number, unAncho:Number, unAlto:Number, tipoGrupo:int):Cuerpo
		{
			var cuerpo:Cuerpo = new Cuerpo (xx,yy,velX,velY,unAncho,unAlto);
			if (tipoGrupo==TIPO_GRUPO_A)
			{
				agregarGrupoA (cuerpo);
			}
			else
			{
				agregarGrupoB (cuerpo);
			}
			return cuerpo;
		}
		
		public function destroyCuerpoGrupo (unCuerpo:Cuerpo)
		{
			var posCuerpo:Number = estaEnArray(grupoA,unCuerpo);
			if (posCuerpo !=-1)
			{
				unCuerpo.destroy();				
				grupoA=borrarPosArray(grupoA,posCuerpo);
				return;
			}
			posCuerpo = estaEnArray(grupoB,unCuerpo);
			if (posCuerpo !=-1)
			{
				unCuerpo.destroy();				
				grupoB=borrarPosArray(grupoB,posCuerpo);
				return;
			}
		}
		
		private function borrarPosArray (unArray:Array,unaPos:Number):Array
		{
			var i:Number = 0;
			var nuevoArray:Array = new Array();
			for (i=0;i<unArray.length;i++)
			{
				if (i!=unaPos)
				{
					nuevoArray.push(unArray[i]);
				}
			}
			return nuevoArray;
		}
		
		
	}
}